package org.acghub.reflection.bytebuddy;

import lombok.extern.slf4j.Slf4j;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.agent.ByteBuddyAgent;
import net.bytebuddy.dynamic.loading.ClassReloadingStrategy;
import net.bytebuddy.implementation.FixedValue;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.matcher.ElementMatchers;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;

/**
 * @Desc
 * @Author miyuki4j
 * @Date 2025/7/23/星期三 14:38
 * @Version 1.0
 */
@Slf4j
public class ByteBuddyTest {

    @Before
    public void before() {
        log.info("before");
    }

    @After
    public void after() {
        log.info("after");
    }

    @Test
    public void test_HelloWorld() throws InstantiationException, IllegalAccessException {
        Class<?> dynamicType = new ByteBuddy().subclass(Object.class).method(ElementMatchers.named("toString")).intercept(FixedValue.value("Hello World!")).make().load(getClass().getClassLoader()).getLoaded();
        Object o = dynamicType.newInstance();
        assertThat(o.toString(), is("Hello World!"));
    }

    @Test
    public void test_Greeting() throws InstantiationException, IllegalAccessException {
        Class<? extends java.util.function.Function> dynamicType = new ByteBuddy()
                .subclass(PrintFunction.class)
                .method(ElementMatchers.named("apply"))
                .intercept(MethodDelegation.to(new GreetingInterceptor())).make()
                .load(getClass().getClassLoader()).getLoaded();
        assertThat((String) dynamicType.newInstance().apply("Byte Buddy"), is("Hello from Byte Buddy"));
    }

    @Test
    public void test_Redefine() throws InstantiationException, IllegalAccessException {
        ByteBuddyAgent.install();
        Foo foo = new Foo();
        new ByteBuddy()
                .redefine(Bar.class)
                .name(Foo.class.getName())
                .make()
                .load(Foo.class.getClassLoader(), ClassReloadingStrategy.fromInstalledAgent());
        assertThat(foo.m(), is("bar"));
    }

    public static class GreetingInterceptor {
        public Object greet(Object argument) {
            log.info("greet: " + argument);
            return "Hello from " + argument;
        }
    }

    public static class PrintFunction implements java.util.function.Function<Object, Object> {
        @Override
        public Object apply(Object t) {
            log.info("apply: " + t);
            return t;
        }
    }

    static class Foo {
        String m() {
            return "foo";
        }
    }

    static class Bar {
        String m() {
            return "bar";
        }
    }

}
